﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DevExpress.XtraEditors;
using DevExpress.XtraBars;
using ProgNetComponents.Collections;
using System.Data;
using ProgNetComponents.Classes;
using System.ComponentModel;
using ProgNetComponents.Ini;
using System.Drawing;
using DevExpress.XtraEditors.Controls;

namespace ProgNetComponentsDx.Options
{
    public abstract class OptionGrabber
    {
        protected abstract NamedObjectCollection _ReadOptions();
        protected abstract bool _SaveOptions();
        protected abstract void _SaveSingleOption(object optionId);
        protected abstract void _SetOptionValue(object optionId, object value, bool save = false, bool updateControls = false);
        
        internal void SetOptionValue(object optionId, object value, bool save = false, bool updateControls = false)
        {
            _SetOptionValue(optionId, value, save, updateControls);
        }
        internal NamedObjectCollection ReadOptions()
        {
            return _ReadOptions();
        }
        internal bool SaveOptions()
        {
            return _SaveOptions();
        }
        internal void SaveSingleOption(object optionId)
        {
            _SaveSingleOption(optionId);
        }
    }
    
    public class SqlCeOptionGrabber : OptionGrabber
    {
        public SqlCeOptionGrabber()
        {
            Manager.AutoLogExceptions = true;
        }
        private ProgNetComponents.Data.SqlCe.SqlCeDataManager _Manager = new ProgNetComponents.Data.SqlCe.SqlCeDataManager();
        public ProgNetComponents.Data.SqlCe.SqlCeDataManager Manager
        {
            get { return _Manager; }
        }

        private DataTable table = null;
        public DataTable Table
        {
            get
            {
                if (table == null)
                {
                    table = new DataTable(TableName);
                    table.Columns.Add(OptionValueColumn);
                    table.Columns.Add(OptionNameColumn);
                    table.PrimaryKey = new DataColumn[] { table.Columns[OptionNameColumn] };
                }
                return table;
            }
        }

        public string TableName
        {
            get;
            set;
        }
        public string OptionNameColumn
        {
            get;
            set;
        }
        public string OptionValueColumn
        {
            get;
            set;
        }

        protected override NamedObjectCollection _ReadOptions()
        {
            NamedObjectCollection c = new NamedObjectCollection();
            PrepareManager();
            DataTable dt = table.Clone();
            if (Manager.FillTable(dt))
            {
                object value;
                Option op;
                string name;
                foreach (DataRow r in dt.Rows)
                {
                    value = r[OptionValueColumn];
                    name = r[OptionNameColumn].AsString();

                    op = OptionCache.GetOption(name);
                    if (op != null)
                    {
                        value = value.ChangeType(op.OptionType);
                        c.Add(name, value);
                    }
                    else
                    {
                        c.Add(name, value);
                    }
                }
            }
            dt.AcceptChanges();
            table.Merge(dt);
            return c;
        }

        protected override void _SetOptionValue(object optionId, object value, bool save = false, bool updateControls = false)
        {
            string option = OptionCache.GetKey(optionId);
            
            DataRow r = Table.SelectFirstRow(OptionNameColumn + " = " + option.EscapeSql());
            if (r == null)
            {
                r = table.NewRow();
                r[OptionNameColumn] = option;
                r.SetColVal(OptionValueColumn, value.AsString());
                Table.Rows.Add(r);
            }
            else
            {
                r.SetColVal(OptionValueColumn, value.AsString());
            }
        }

        protected override bool _SaveOptions()
        {
            DataTable dt = Table.GetChanges();

            bool result = Manager.UpdateTable(Table);

            if (result)
            {
                Table.AcceptChanges();
                if (dt != null)
                {
                    foreach (DataRow r in dt.Rows)
                    {
                        OptionCache.OnOptionChanged(r[OptionNameColumn].AsString());
                    }
                }
            }
            return result;
        }

        private void PrepareManager()
        {
            if (Manager.TableDefsCount == 0)
                Manager.AddTableDef(Table, "SELECT " + OptionNameColumn + "," + OptionValueColumn + " FROM " + TableName);
        }

        protected override void _SaveSingleOption(object optionId)
        {
            DataTable dt = table.Clone();
            string option = OptionCache.GetKey(optionId);
            DataRow r = table.SelectFirstRow(OptionNameColumn + " = " + option.EscapeSql());
            if (r != null)
            {
                dt.ImportRow(r);

                if (Manager.UpdateTable(dt))
                    r.AcceptChanges();
                else
                    Manager.LastException.LogError();
            }
        }
    }

    public class IniOptionGrabber : OptionGrabber
    {
        private IniFile ini;
        public IniOptionGrabber(string file)
        {
            ini = new IniFile(file);
        }
        protected override NamedObjectCollection _ReadOptions()
        {
            ini.ReadIni();
            NamedObjectCollection val = new NamedObjectCollection();
            string optionName;
            string optionGroup;
            string optionValue;
            Option o;

            foreach (KeyValuePair<string, Dictionary<string,string>> kvp in ini.IniValues)
            {
                optionGroup = kvp.Key;
                foreach (KeyValuePair<string, string> key in kvp.Value)
                {
                    optionName = optionGroup + "." + key.Key;
                    optionValue = key.Value;
                    o = OptionCache.GetOption(optionName);
                    if (o != null)
                    {
                        val.Add(optionName, optionValue.ChangeType(o.OptionType));
                    }
                    else
                    {
                        val.Add(optionName, optionValue);
                    }
                }
            }
            return val;
        }

        protected override bool _SaveOptions()
        {
            return ini.SaveIni();
        }
        protected override void _SetOptionValue(object optionId, object value, bool save = false, bool updateControls = false)
        {
            string option = OptionCache.GetKey(optionId);

            int idx = option.LastIndexOf('.');
            string group  ="";
            string name ="";
            if (idx != -1)
            {
                group = option.SubstringSafe(0, idx);
                name = option.SubstringSafe(idx);
            }
            else
            {
                group = "MAIN";
                name = option;
            }

            if (group.IsNotNull() && name.IsNotNull())
                ini.WriteValueToCache(group, name, value.AsString());
        }
        protected override void _SaveSingleOption(object optionId)
        {
            string option = OptionCache.GetKey(optionId);

           // Option o = OptionCache.GetOption(optionId);
            //if (o != null)
            {
                int idx = option.LastIndexOf('.');
                string group  ="";
                string name ="";
                if (idx != -1)
                {
                    group = option.SubstringSafe(0, idx);
                    name = option.SubstringSafe(idx);
                }
                else
                {
                    group = "MAIN";
                    name = option;
                }

                if (group.IsNotNull() && name.IsNotNull())
                {
                    ini.WriteValueToFile(group, name, OptionCache.GetOptionValue(optionId).AsString());
                }
            }
        }
    }
}
